package com.kfm.base.single;

import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;

/**
 * 单例模式
 * 单实例，在项目中只有一个实例。
 * 步骤：
 * 1. 构造方法私有(private)
 * 2. 提供获取唯一实例的方式
 */
public class Singleton {

    // 饿汉
    private static final Singleton SINGLETON = new Singleton();

    // 构造私有
    private Singleton() {
        if (SINGLETON != null) {
            throw new RuntimeException("已有实例");
        }
    }

    public static Singleton getInstance() {
        return SINGLETON;
    }
}

// 懒汉
class LazySingleton {

    private static LazySingleton singleton;

    private LazySingleton() {}

    public static LazySingleton getInstance() {
        if (singleton == null) {
            singleton = new LazySingleton();
        }
        return singleton;
    }
}

// 枚举
enum EnumSingleton {

    SINGLETON;


}

// 静态嵌套类
class OutClass {

    private OutClass() {
        if (StaticNestedClass.outClass != null) {
            throw new RuntimeException("已有实例");
        }
    }

    // 静态嵌套类
    private static class StaticNestedClass {
        private static final OutClass outClass = new OutClass();
    }

    public static OutClass getInstance() {
        return StaticNestedClass.outClass;
    }
}


class Test {

    public static void main(String[] args) {
        OutClass s = OutClass.getInstance();
        OutClass s1 = OutClass.getInstance();
        System.out.println(s);
        System.out.println(s1);
        System.out.println(s == s1);


        Singleton instance = Singleton.getInstance();

        try {
            // 反射，运行时获取类信息
            Constructor<Singleton> c = Singleton.class.getDeclaredConstructor();
            c.setAccessible(true);
            Singleton singleton = c.newInstance();
            System.out.println(instance);
            System.out.println(singleton);
            System.out.println(instance == singleton);
        } catch (NoSuchMethodException e) {
            throw new RuntimeException(e);
        } catch (InvocationTargetException e) {
            throw new RuntimeException(e);
        } catch (InstantiationException e) {
            throw new RuntimeException(e);
        } catch (IllegalAccessException e) {
            throw new RuntimeException(e);
        }

    }
}